﻿//-----------------------------------------------------------------------
// <copyright file="OtherUsersDisplay.xaml.cs" company="AFS">
// Copyright (c) AFS. All rights reserved.
//
//    This file is part of Chatbox.
//
//    Chatbox is free software: you can redistribute it and/or modify
//    it under the terms of the GNU Lesser General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    any later version.
//
//    Chatbox is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//    GNU Lesser General Public License for more details.
//
//    You should have received a copy of the GNU Lesser General Public License
//    along with Chatbox. If not, see http://www.gnu.org/copyleft/lesser.html
// </copyright>
//----------------------------------------------------------------------- 
namespace ChatBox.UI.Controls
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;

    using ChatBox.DomainObjects.Settings;
    using ChatBox.DomainObjects.XmlFeedObjects;
    using ChatBox.Interfaces;
    using ChatBox.UI.ViewModels;
    using ChatBox.UI.Windows.SendPrivateMessage;
    using ChatBox.XamlUtility;

    /// <summary>
    /// Interaction logic for OtherUsersDisplay.xaml
    /// </summary>
    public partial class OtherUsersDisplay : UserControl
    {
        /// <summary>
        /// user interface settings data 
        /// </summary>
        private UISettingsData uiSettingsData;

        /// <summary>
        /// Initializes a new instance of the OtherUsersDisplay class
        /// </summary>
        public OtherUsersDisplay()
        {
            InitializeComponent();
        }

        #region properties

        /// <summary>
        /// Gets or sets how to configure hyperlinks
        /// </summary>
        public HyperlinkContext HyperlinkContext { get; set; }

        /// <summary>
        /// Gets or sets chat functionality
        /// </summary>
        public IUISettingsRepository UISettingsRepository { get; set; }

        /// <summary>
        /// Gets or sets the command to tell the application about operations completed 
        /// </summary>
        public ICommand OperationCompletedCommand { get; set; }

        #endregion

        /// <summary>
        /// Show the list of other users in the flowdocument
        /// </summary>
        /// <param name="users">the users to display</param>
        public void ShowOtherUsers(IEnumerable<OtherUser> users)
        {
            this.uiSettingsData = this.UISettingsRepository.ReadSettings();

            this.otherUsersStackPanel.Children.Clear();
            foreach (var user in users)
            {
                this.AddUserToList(user);
            }
        }

        /// <summary>
        /// Append flags text to the stringbuilder
        /// </summary>
        /// <param name="contentFlags">the flags text</param>
        /// <param name="text">the flag to append</param>
        private static void AppendFlagText(StringBuilder contentFlags, string text)
        {
            if (contentFlags.Length > 0)
            {
                contentFlags.Append(", ");
            }

            contentFlags.Append(text);
        }

        /// <summary>
        /// Add content for the user status flags
        /// </summary>
        /// <param name="contentSpan">the document to add content to</param>
        /// <param name="user">the user to link to</param>
        /// <returns>the toolip string for user status description</returns>
        private static string AddUserStatusFlags(Span contentSpan, OtherUser user)
        {
            StringBuilder contentFlagsLong = new StringBuilder();
            if (user.HasAnySpecialStatus)
            {
                string contentFlags = " ";
                if (user.Administrator)
                {
                    contentFlags += "A";
                    AppendFlagText(contentFlagsLong, "Administrator");
                }

                if (user.ChannelOperator)
                {
                    contentFlags += "+";
                    AppendFlagText(contentFlagsLong, "Channel Operator");
                }

                if (user.ContentEditor)
                {
                    contentFlags += "E";
                    AppendFlagText(contentFlagsLong, "Content Editor");
                }

                if (user.Committer)
                {
                    contentFlags += "C";
                    AppendFlagText(contentFlagsLong, "Committer");
                }

                if (user.Developer)
                {
                    contentFlags += "D";
                    AppendFlagText(contentFlagsLong, "Developer");
                }

                if (user.IsBanned)
                {
                    contentFlags += "B";
                    AppendFlagText(contentFlagsLong, "Banned");
                }

                contentSpan.Inlines.Add(new Italic(new Run(contentFlags)));
            }

            return contentFlagsLong.ToString();
        }
        
        /// <summary>
        /// Add a user to the other users list
        /// </summary>
        /// <param name="user">the user to add</param>
        private void AddUserToList(OtherUser user)
        {
            Span contentSpan = new Span();
            Hyperlink userHyperlink = new Hyperlink(new Run(user.UserName));
            userHyperlink.NavigateUri = new Uri(this.HyperlinkContext.SitePrefix + "/node/" + user.User.NodeId);
            this.HyperlinkContext.SetContextOnHyperlink(userHyperlink);
            contentSpan.Inlines.Add(userHyperlink);

            string statusFlagsTooltip = AddUserStatusFlags(contentSpan, user);

            if (this.uiSettingsData.ShowSendPrivateMessageButtonInOtherUsers)
            {
                this.AddPrivateMessageToUserButton(contentSpan, user);
            }

            // wrap it all up in a label
            Label userLabel = new Label();
                
            // pad left and right, keep close top and bottom
            userLabel.Padding = new Thickness(2, 0, 2, 0);
            userLabel.Content = contentSpan;
            userLabel.FontSize = this.uiSettingsData.OtherUsersFontSize;
            userLabel.FontFamily = new FontFamily("Georgia");

            // make the toolip
            OtherUserTooltipViewModel viewModel = new OtherUserTooltipViewModel();
            viewModel.UserName = user.UserName;
            viewModel.SpecialStatusText = statusFlagsTooltip;
            viewModel.HasAnySpecialStatus = user.HasAnySpecialStatus.ToVisibility();
            viewModel.ExperiencePoints = "XP:" + user.ExperiencePoints.ToString("### ### ##0", CultureInfo.InvariantCulture);

            userLabel.ToolTip = new OtherUserTooltip(viewModel);

            this.otherUsersStackPanel.Children.Add(userLabel);
        }

        /// <summary>
        /// Add a button to send a private message to the user
        /// </summary>
        /// <param name="contentSpan">the document to add content to</param>
        /// <param name="user">the user to link to</param>
        private void AddPrivateMessageToUserButton(Span contentSpan, OtherUser user)
        {
            Button privateMessageButton = new Button();
            privateMessageButton.Style = this.FindStyle("SendPrivateMessageButtonStyle");

            privateMessageButton.ToolTip = "Private message to " + user.UserName;
            privateMessageButton.Click += (o, r) => this.PrivateMessageTo(user);

            // The button looks better aligned at the bottom, like this
            Span verticallyAlignedSpan = new Span();
            verticallyAlignedSpan.Inlines.Add(privateMessageButton);
            verticallyAlignedSpan.BaselineAlignment = BaselineAlignment.Bottom;

            contentSpan.Inlines.Add(verticallyAlignedSpan);
        }

        /// <summary>
        /// Launch the private message send dialog
        /// </summary>
        /// <param name="user">the user to send the message to</param>
        private void PrivateMessageTo(OtherUser user)
        {
            ShowSendPrivateMessageCommand command = Locator.Resolve<ShowSendPrivateMessageCommand>();
            command.Execute(new ShowPrivateMessageParameters(
                Window.GetWindow(this), 
                user.User, 
                this.HyperlinkContext,
                this.OperationCompletedCommand));
        }
    }
}
